package com.three.monitor.server;

import com.three.api.service.BaseService;
import com.three.api.service.Listener;
import com.three.config.common.IConfig;
import com.three.monitor.data.MonitorResult;
import com.three.monitor.data.ResultCollector;
import com.three.monitor.quota.impl.JVMInfo;
import com.three.tools.thread.ThreadNames;
import com.three.tools.thread.pool.ThreadPoolManager;
import com.three.utils.JVMUtils;
import com.three.utils.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * Created by Mathua on 2017/5/25.
 */
public class MonitorService extends BaseService implements Runnable {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    public static final MonitorService I = new MonitorService();

    private static final int FIRST_DUMP_JSTACK_LOAD_AVG = 2,
            SECOND_DUMP_JSTACK_LOAD_AVG = 4,
            THIRD_DUMP_JSTACK_LOAD_AVG = 6,
            FIRST_DUMP_JMAP_LOAD_AVG = 4;

    private static final String dumpLogDir = IConfig.chess.monitor.dump_dir;
    private static final boolean dumpEnabled = IConfig.chess.monitor.dump_stack;
    private static final boolean printLog = IConfig.chess.monitor.print_log;
    private static final long dumpPeriod = IConfig.chess.monitor.dump_period.getSeconds();

    private volatile boolean dumpFirstJstack = false;
    private volatile boolean dumpSecondJstack = false;
    private volatile boolean dumpThirdJstack = false;
    private volatile boolean dumpJmap = false;

    private final ResultCollector collector = new ResultCollector();

    private Thread thread;

    @Override
    public void run() {
        while (isRunning()) {
            // 收集监控结果
            MonitorResult result = collector.collect();

            if (printLog) {
//                LogUtils.MONITOR.info(result.toJson());
            }

            if (dumpEnabled) {
                dump();
            }

            try {
                TimeUnit.SECONDS.sleep(dumpPeriod);
            } catch (InterruptedException e) {
                if (isRunning()) stop();
            }
        }
    }

    @Override
    protected void doStart(Listener listener) throws Throwable {
        if (printLog || dumpEnabled) {
            thread = ThreadPoolManager.I.newThread(ThreadNames.T_MONITOR, this);
            thread.setDaemon(true);
            thread.start();
        }
        listener.onSuccess();
    }

    @Override
    protected void doStop(Listener listener) throws Throwable {
        if (thread != null && thread.isAlive()) thread.interrupt();
        listener.onSuccess();
    }

    /**
     * 转储监控信息
     */
    private void dump() {
        double load = JVMInfo.I.load();
        if (load > FIRST_DUMP_JSTACK_LOAD_AVG) {
            if (!dumpFirstJstack) {
                dumpFirstJstack = true;
                JVMUtils.dumpJstack(dumpLogDir);
            }
        }

        if (load > SECOND_DUMP_JSTACK_LOAD_AVG) {
            if (!dumpSecondJstack) {
                dumpSecondJstack = true;
                JVMUtils.dumpJmap(dumpLogDir);
            }
        }

        if (load > THIRD_DUMP_JSTACK_LOAD_AVG) {
            if (!dumpThirdJstack) {
                dumpThirdJstack = true;
                JVMUtils.dumpJmap(dumpLogDir);
            }
        }

        if (load > FIRST_DUMP_JMAP_LOAD_AVG) {
            if (!dumpJmap) {
                dumpJmap = true;
                JVMUtils.dumpJmap(dumpLogDir);
            }
        }
    }
}
